#include "buttons.h"
#include "utils.h"
#include "fsl_debug_console.h"
#include <tos_k.h>


typedef struct button_context_t
{
    buttons_callback_t callback;
    k_tick_t pressed_time;
    buttons_status_t pressed_status;
    buttons_status_t comming_pressed_status;
    buttons_status_t old_comming_pressed_status;
    int in_long_pressed;
} button_context_t;


static void stub_btn_callback(int event);


#define BTN_CONTEXT_INITIALIZER { stub_btn_callback, 0, BTN_STATUS_NON_INIT, BTN_STATUS_NON_INIT, BTN_STATUS_RELEASE, 0 }
#define BTN_LONG_PRESSED_TIME 1000

#define is_pressed(val) BTN_STATUS_PRESSED == (val)
#define has_status(val) BTN_STATUS_PRESSED == (val) || BTN_STATUS_RELEASE == (val)


static button_context_t g_btn_contexts[BTN_ID_COUNT] = {
    BTN_CONTEXT_INITIALIZER,
    BTN_CONTEXT_INITIALIZER,
};
static k_task_t g_button_task;
static k_mutex_t g_button_mutex;
static uint8_t g_task_stk[256];
static uint8_t g_run = 0;


static void buttons_main(void * arg)
{
    while (g_run)
    {
        k_tick_t cur = get_sys_time();
        for (buttons_id_t id = BTN_ID_1; id < BTN_ID_COUNT; ++id)
        {
            int event = 0;
            tos_mutex_pend(&g_button_mutex);
            if (has_status(g_btn_contexts[id].comming_pressed_status))
            {
                if (g_btn_contexts[id].comming_pressed_status != g_btn_contexts[id].pressed_status)
                {
                    if (BTN_STATUS_PRESSED == g_btn_contexts[id].comming_pressed_status)
                    {
                        g_btn_contexts[id].pressed_time = get_sys_time();
                        event |= BTN_EVENT_PRESSED;
                    } else
                    {
                        if ((cur - g_btn_contexts[id].pressed_time) < BTN_LONG_PRESSED_TIME)
                        {
                            event |= BTN_EVENT_CLICK;
                        }
                        event |= BTN_EVENT_RELEASED;
                        g_btn_contexts[id].in_long_pressed = 0;
                    }
                    g_btn_contexts[id].pressed_status = g_btn_contexts[id].comming_pressed_status;
                } else
                {
                    if (BTN_STATUS_PRESSED == g_btn_contexts[id].pressed_status)
                    {
                        if ((cur - g_btn_contexts[id].pressed_time) >= BTN_LONG_PRESSED_TIME
                            && !g_btn_contexts[id].in_long_pressed)
                        {
                            event |= BTN_EVENT_LONG_PRESS;
                            g_btn_contexts[id].in_long_pressed = 1;
                        }
                    }
                }
                g_btn_contexts[id].comming_pressed_status = BTN_STATUS_NON_INIT;
            } else  // No comming status
            {
                if (BTN_STATUS_PRESSED == g_btn_contexts[id].pressed_status)
                {
                    if ((cur - g_btn_contexts[id].pressed_time) >= BTN_LONG_PRESSED_TIME
                        && !g_btn_contexts[id].in_long_pressed)
                    {
                        event |= BTN_EVENT_LONG_PRESS;
                        g_btn_contexts[id].in_long_pressed = 1;
                    }
                }
            }
            tos_mutex_post(&g_button_mutex);
            if (event > 0)
            {
                g_btn_contexts[id].callback(event);
            }
        }
        tos_task_delay(10);
    }
}

void buttons_init(void)
{
	tos_mutex_create(&g_button_mutex);
    g_run = 1;
    tos_task_create(&g_button_task, "buttons_main", buttons_main, NULL, 4, g_task_stk, sizeof(g_task_stk), 0);
}

void buttons_deinit(void)
{
    // TODO:
}

static void stub_btn_callback(int event)
{}

void buttons_set_callback(buttons_id_t id, buttons_callback_t callback)
{
    switch (id)
    {
    case BTN_ID_1:
    case BTN_ID_2:
        break;
    default:
        return;
    }
    if (K_NULL == callback)
    {
        callback = stub_btn_callback;
    }
    g_btn_contexts[id].callback = callback;
}

void buttons_set_values(buttons_status_t btn1_status, buttons_status_t btn2_status)
{
    // tos_mutex_pend(&g_button_mutex);
    if (!g_run)  // Not inited
    {
        return;
    }
    if (g_btn_contexts[BTN_ID_1].old_comming_pressed_status != btn1_status)
    {
        g_btn_contexts[BTN_ID_1].comming_pressed_status = btn1_status;
        g_btn_contexts[BTN_ID_1].old_comming_pressed_status = btn1_status;
    }
    if (g_btn_contexts[BTN_ID_2].old_comming_pressed_status != btn2_status)
    {
        g_btn_contexts[BTN_ID_2].comming_pressed_status = btn2_status;
        g_btn_contexts[BTN_ID_2].old_comming_pressed_status = btn2_status;
    }
    // tos_mutex_post(&g_button_mutex);
}
